﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BuildOptimizer
{
    class BoCommandBuildDrone : BoCommand
    {
        private const float _min = 50.0f;
        private const float _gas = 0.0f;
        private const float _supply = 1.0f;
        private const int _time = 17;
        private const commandID _commandID = commandID.buildDrone;

        private int _hatchIndex = -1;
        private int _baseIndex = -1;
        public BoCommandBuildDrone(int hatchIndex, int baseIndex)
        {
            _hatchIndex = hatchIndex;
            _baseIndex = baseIndex;
        }

        public override void execute(BoGoal goal, BoDecisionNode node)
        {
            node.gameState.removeMineralsAndGas(_min, _gas);
            node.gameState.getHatchery(_hatchIndex).removeLarvaeForUnit();
            node.gameState.startBuildingUnit((int)Units.Drone);

            checkIfMoreRequired(goal, node);
            BoTask t = new BoTask(_time, delegate(BoDecisionNode n)
            {
                n.gameState.finishedBuildingUnit((int)Units.Drone);
                n.gameState.getHatcheryAtResources(_baseIndex).moveDroneToMinerals();

                int baseStart = n.gameState.getHatchery(_hatchIndex).baseIndex;
                int baseEnd = _baseIndex;
                int travelTime = 15 * (baseEnd - baseStart) + 2;

                BoTask t2 = new BoTask(travelTime, delegate(BoDecisionNode n2)
                {
                    n2.gameState.getHatcheryAtResources(_baseIndex).makeDroneMineMinerals();
                });
                n.gameState.addTask(t2);
            });
            node.gameState.addTask(t);
        }

        public static bool checkIfMoreRequired(BoGoal goal, BoDecisionNode node)
        {
            //user wants the computer to figure out the number of drones
            int nbRequiredDrones = goal.nbUnitsRequired((int)Units.Drone);
            int nbCurrentDrones = node.gameState.nbUnitsBeingBuilt((int)Units.Drone) + node.gameState.nbUnitsBuilt((int)Units.Drone);
            if (nbRequiredDrones == -1)
            {
                return true;
            }

            //if user wants the computer to figure out the number of buildings, then
            //the computer gets free reign over the number of drones
            bool unlimitedDrones = false;
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.Hatchery) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.Lair) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.Hive) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.SpawningPool) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.EvolutionChamber) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.RoachWarren) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.HydraliskDen) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.BanelingNest) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.InfestationPit) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.GreaterSpire) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.UltraliskCavern) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.Extractor) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.Spire) == -1);
            unlimitedDrones = unlimitedDrones || (goal.nbBuildingsRequired((int)Buildings.NydusNetwork) == -1);
            if (unlimitedDrones)
            {
                return true;
            }

            //build enough drones to make buildings
            int nbRequiredBuildings = 0;
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.Hatchery);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.Lair);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.Hive);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.SpawningPool);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.EvolutionChamber);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.RoachWarren);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.HydraliskDen);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.BanelingNest);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.InfestationPit);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.GreaterSpire);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.UltraliskCavern);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.Extractor);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.Spire);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.SpineCrawler);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.SporeCrawler);
            nbRequiredBuildings += goal.nbBuildingsRequired((int)Buildings.NydusNetwork);

            int nbCurrentBuildings = 0;
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.Hatchery) + node.gameState.nbBuildingsBuilt((int)Buildings.Hatchery);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.Lair) + node.gameState.nbBuildingsBuilt((int)Buildings.Lair);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.Hive) + node.gameState.nbBuildingsBuilt((int)Buildings.Hive);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.SpawningPool) + node.gameState.nbBuildingsBuilt((int)Buildings.SpawningPool);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.EvolutionChamber) + node.gameState.nbBuildingsBuilt((int)Buildings.EvolutionChamber);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.RoachWarren) + node.gameState.nbBuildingsBuilt((int)Buildings.RoachWarren);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.HydraliskDen) + node.gameState.nbBuildingsBuilt((int)Buildings.HydraliskDen);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.BanelingNest) + node.gameState.nbBuildingsBuilt((int)Buildings.BanelingNest);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.InfestationPit) + node.gameState.nbBuildingsBuilt((int)Buildings.InfestationPit);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.GreaterSpire) + node.gameState.nbBuildingsBuilt((int)Buildings.GreaterSpire);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.UltraliskCavern) + node.gameState.nbBuildingsBuilt((int)Buildings.UltraliskCavern);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.Extractor) + node.gameState.nbBuildingsBuilt((int)Buildings.Extractor);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.Spire) + node.gameState.nbBuildingsBuilt((int)Buildings.Spire);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.SpineCrawler) + node.gameState.nbBuildingsBuilt((int)Buildings.SpineCrawler);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.SporeCrawler) + node.gameState.nbBuildingsBuilt((int)Buildings.SporeCrawler);
            nbCurrentBuildings += node.gameState.nbBuildingsBeingBuilt((int)Buildings.NydusNetwork) + node.gameState.nbBuildingsBuilt((int)Buildings.NydusNetwork);

            if (nbCurrentDrones < nbRequiredDrones + (nbRequiredBuildings - nbCurrentBuildings))
            {
                return true;
            }

            node.dismissCommand((int)commandID.buildDrone);
            return false;
        }
        public static bool isAvailable(BoGameState gs, int hatchIndex)
        {
            if (gs.getHatchery(hatchIndex).nbLarvae < 1)
            {
                return false;
            }
            return true;
        }
        public static bool isAffordable(BoGameState gs)
        {
            if (!gs.isResourcesAvailable(_min, _gas, _supply))
            {
                return false;
            }
            return true;
        }

        public override int getCommandCode()
        {
            int code = ((int)_commandID * 100) + (_hatchIndex * 10) + _baseIndex;
            return code;
        }
        public override commandID getCommandID()
        {
            return _commandID;
        }
        public override string toString()
        {
            string str = "Hatchery " + _hatchIndex + " -> Drone to base " + _baseIndex;
            return str;
        }
    }
}
